package smallfrench.ui;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.SwingUtilities;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;

/**
 * Surligne la ligne du curseur.
 */
public class SurligneurLigne implements Highlighter.HighlightPainter,
CaretListener, MouseListener, MouseMotionListener {
	private JTextComponent component;

	private static Color COULEUR_NORMALE = new Color(240, 245, 255);
	private static Color COULEUR_ERREUR = new Color(240, 200, 200);

	private Color couleur;

	private Rectangle lastView;

	/**
	 * 
	 * @param component Le {@link JTextComponent} qui comportera la ligne
	 * surlignée.
	 */
	public SurligneurLigne(JTextComponent component) {
		this.component = component;
		couleur = COULEUR_NORMALE;

		component.addCaretListener(this);
		component.addMouseListener(this);
		component.addMouseMotionListener(this);

		try {
			component.getHighlighter().addHighlight(0, 0, this);
		} catch (BadLocationException ble) {
		}
	}

	/**
	 * Change la couleur du surlignage.
	 */
	public void setCouleurNormale() {
		couleur = COULEUR_NORMALE;
	}

	/**
	 * Change la couleur du surlignage.
	 */
	public void setCouleurErreur() {
		couleur = COULEUR_ERREUR;
	}

	@Override
	public void paint(Graphics g, int p0, int p1,
			Shape bounds, JTextComponent c) {
		try {
			Rectangle r = c.modelToView(c.getCaretPosition());
			g.setColor(couleur);
			g.fillRect(0, r.y, c.getWidth(), r.height);

			if (lastView == null)
				lastView = r;
		} catch (BadLocationException ble) {
			System.out.println(ble);
		}
	}

	/**
	 * Quand le curseur se déplace.
	 */
	private void resetHighlight() {

		couleur = COULEUR_NORMALE;

		// Use invokeLater to make sure updates to the Document are completed,
		// otherwise Undo processing causes the modelToView method to loop.

		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				try {
					int offset = component.getCaretPosition();
					Rectangle currentView = component.modelToView(offset);

					// On désurligne la ligne précédemment surlignée
					if (lastView.y != currentView.y) {
						component.repaint(0, lastView.y, component.getWidth(),
								lastView.height);
						lastView = currentView;
					}
				} catch (BadLocationException ble) {
				}
			}
		});
	}

	// Implémentation CaretListener

	@Override
	public void caretUpdate(CaretEvent e) {
		resetHighlight();
	}

	// Implémentation MouseListener

	@Override
	public void mousePressed(MouseEvent e) {
		resetHighlight();
	}

	@Override
	public void mouseClicked(MouseEvent e) {}

	@Override
	public void mouseEntered(MouseEvent e) {}

	@Override
	public void mouseExited(MouseEvent e) {}

	@Override
	public void mouseReleased(MouseEvent e) {}

	// Implémentation MouseMotionListener

	@Override
	public void mouseDragged(MouseEvent e) {
		resetHighlight();
	}

	@Override
	public void mouseMoved(MouseEvent e) {}
}
